package com.tcm.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.tcm.common.enums.CachePrefix;
import com.tcm.config.AppProperties;
import com.tcm.entity.*;
import com.tcm.entity.bo.UserCacheBo;
import com.tcm.entity.dto.ScoreUpdateDto;
import com.tcm.entity.resp.PageR;
import com.tcm.entity.vo.*;
import com.tcm.mapper.BookItemMapper;
import com.tcm.mapper.ItemStudentMapper;
import com.tcm.mapper.TeacherMapper;
import com.tcm.service.*;
import com.tcm.utils.ItemUtil;
import com.tcm.utils.RedisUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 按章节练习记录业务实现类
 * @author Guqier
 * @description 针对表【ts_item_student(按章节练习学生答题记录)】的数据库操作Service实现
 * @createDate 2023-08-20 16:56:55
 */
@Service
@RequiredArgsConstructor
public class ItemStudentServiceImpl extends ServiceImpl<ItemStudentMapper, ItemStudent>
        implements ItemStudentService {

    private final RedisUtil redisUtil;

    private final ScoreService scoreService;

    private final ClozeItemService clozeItemService;

    private final SubjectItemService subjectItemService;

    private final BookService bookService;

    private final BookItemMapper bookItemMapper;

    private final CodeService codeService;

    private final ImageService imageService;

    private final ItemService itemService;

    private final CollectService collectService;

    private final RoleService roleService;

    private final TeacherMapper teacherMapper;

    private final UserService userService;

    /**
     * 保存学生题目练习记录
     * @param resp       题目评判结果
     * @param currUserId 当前 登录用户ID
     * @return 处理结果
     * @throws JsonProcessingException JSON序列化异常
     */
    @Override
    @Transactional
    public boolean saveItemStudent(ItemCorrectResp resp, Long currUserId, Integer type) throws JsonProcessingException {
        // 获取当前用户信息
        UserCacheBo userCacheBo = redisUtil.getCacheObject(CachePrefix.PC_USER_TOKEN.getCacheKey(currUserId.toString()));
        return saveItemStudent(resp, userCacheBo, type);
    }

    /**
     * 保存学生题目练习记录
     * @param resp        题目评判结果
     * @param userCacheBo 用户信息
     * @return 处理结果
     * @throws JsonProcessingException JSON序列化异常
     */
    @Override
    @Transactional
    public boolean saveItemStudent(ItemCorrectResp resp, UserCacheBo userCacheBo, Integer type) throws JsonProcessingException {
        // 查询题目是否已经有记录
        ItemStudent itemStudent = this.getOne(new LambdaQueryWrapper<ItemStudent>().eq(ItemStudent::getItemId, resp.getItemId()).eq(ItemStudent::getAccount, userCacheBo.getAccount()));
        int score = 0;
        boolean flag;
        if (Objects.isNull(itemStudent)) {
            ItemStudent is = new ItemStudent();
            is.setItemId(resp.getItemId());
            is.setItemType(resp.getType());
            is.setAccount(userCacheBo.getAccount());
            is.setScore(resp.getScore());
            is.setType(type);
            is.setAns(ItemUtil.getUserItemJsonAns(resp));
            is.setCreateUser(userCacheBo.getId());
            is.setUpdateUser(userCacheBo.getId());
            //判断是否是错题
            double v = (double) resp.getScore() / resp.getTotalScore();
            is.setWrongCount(v < 0.7 ? 1 : 0);
            score = resp.getScore();
            flag = this.save(is);
        } else {
            itemStudent.setAns(ItemUtil.getUserItemJsonAns(resp));
            itemStudent.setUpdateUser(userCacheBo.getId());
            // 判断错题
            double v = (double) resp.getScore() / resp.getTotalScore();
            itemStudent.setWrongCount(v < 0.7 ? itemStudent.getWrongCount() + 1 : itemStudent.getWrongCount());
            int scoreDiff = resp.getScore() - itemStudent.getScore();
            if (scoreDiff > 0) {// 如果分数大于零，则更新积分
                itemStudent.setScore(resp.getScore());
                score = scoreDiff;
            }
            flag = this.updateById(itemStudent);
        }
        if (flag) {
            // 保存学生积分
            if (score > 0) {
                ScoreUpdateDto scoreUpdateDto = new ScoreUpdateDto();
                scoreUpdateDto.setNum(score);
                scoreUpdateDto.setAccount(userCacheBo.getAccount());
                scoreUpdateDto.setType(0);
                scoreService.saveScore(scoreUpdateDto, userCacheBo.getId());
            }
            return true;
        } else {
            return false;
        }
    }

    /**
     * 获取按章节练习练习记录
     * @param currUserId 当前登录用户ID
     * @return 练习记录
     */
    @Override
    public List<ItemStudentHistoryResp> getChapterExerciseHistory(Long currUserId) {
        // 获取当前用户信息
        UserCacheBo userCacheBo = redisUtil.getCacheObject(CachePrefix.PC_USER_TOKEN.getCacheKey(currUserId.toString()));
        // 获取当前学生所有答题记录
        List<ItemStudent> itemStudentList = this.list(
                new LambdaQueryWrapper<ItemStudent>()
                        .eq(ItemStudent::getAccount, userCacheBo.getAccount())
                        .eq(ItemStudent::getType, 0)
                        .orderByDesc(ItemStudent::getCreateTime));
        // 获取主观题ID列表
        List<Long> subjectIds = itemStudentList
                .stream()
                .filter(itemStudent -> itemStudent.getItemType().equals(AppProperties.ITEM_TYPE_SUBJECT))
                .map(ItemStudent::getItemId)
                .collect(Collectors.toList());
        // 获取填空题ID列表
        List<Long> clozeIds = itemStudentList
                .stream()
                .filter(itemStudent -> itemStudent.getItemType().equals(AppProperties.ITEM_TYPE_CLOZE))
                .map(ItemStudent::getItemId)
                .collect(Collectors.toList());
        // 准备数据
        List<Long> ids = itemStudentList.stream().map(ItemStudent::getItemId).collect(Collectors.toList());
        List<BookItem> bookItems = bookItemMapper.selectList(
                new LambdaQueryWrapper<BookItem>()
                        .in(!CollectionUtils.isEmpty(ids), BookItem::getItemId, ids)
                        .apply(CollectionUtils.isEmpty(ids), "1 != 1")
                        .orderByAsc(BookItem::getCreateTime));
        List<Book> books = bookService.getBookList();
        // 构造结果集
        List<ItemStudentHistoryResp> result = new ArrayList<>();
        // 获取题目信息
        List<SubjectItem> subjectItems = CollectionUtils.isEmpty(subjectIds) ? null : subjectItemService.listByIds(subjectIds);
        List<ClozeItem> clozeItems = CollectionUtils.isEmpty(clozeIds) ? null : clozeItemService.listByIds(clozeIds);
        for (ItemStudent itemStudent : itemStudentList) {
            // 判断题目类型
            if (itemStudent.getItemType().equals(AppProperties.ITEM_TYPE_SUBJECT) && subjectItems != null) {
                subjectItems.stream().filter(subjectItem -> subjectItem.getId().equals(itemStudent.getItemId())).findFirst().ifPresent(subjectItem -> {
                    // 获取题目所属章节
                    List<BookListResult> bookListResults = bookService.getBooksOfItem(subjectItem.getId(), bookItems, books).get(0);
                    BookListResult chapter = bookListResults.get(0);

                    ItemStudentHistoryResp resp = new ItemStudentHistoryResp();
                    resp.setChapterId(chapter.getId());
                    Collections.reverse(bookListResults);
                    resp.setChapter(bookListResults.stream().map(BookListResult::getName).collect(Collectors.joining("/")));
                    resp.setContent(subjectItem.getContent());
                    resp.setTime(itemStudent.getCreateTime());
                    // 查找当前题目所在序号
                    List<BookItem> bookItemsList = bookItemMapper.selectList(new LambdaQueryWrapper<BookItem>().eq(BookItem::getBookId, chapter.getId()).orderByAsc(BookItem::getCreateTime));
                    List<BookItem> collect = bookItemsList.stream().filter(bookItem -> bookItem.getBookId().equals(chapter.getId())).collect(Collectors.toList());
                    collect.stream().filter(bookItem -> bookItem.getItemId().equals(subjectItem.getId())).findFirst().ifPresent(bookItem -> resp.setCurrent(collect.indexOf(bookItem) + 1));
                    result.add(resp);

                });
            } else if (itemStudent.getItemType().equals(AppProperties.ITEM_TYPE_CLOZE) && clozeItems != null) {
                clozeItems.stream().filter(clozeItem -> clozeItem.getId().equals(itemStudent.getItemId())).findFirst().ifPresent(clozeItem -> {
                    List<BookListResult> bookListResults = bookService.getBooksOfItem(clozeItem.getId(), bookItems, books).get(0);
                    BookListResult chapter = bookListResults.get(0);

                    ItemStudentHistoryResp resp = new ItemStudentHistoryResp();
                    resp.setChapterId(chapter.getId());
                    Collections.reverse(bookListResults);
                    resp.setChapter(bookListResults.stream().map(BookListResult::getName).collect(Collectors.joining("/")));
                    resp.setContent(clozeItem.getMarkContent());
                    resp.setTime(itemStudent.getCreateTime());
                    // 查找当前题目所在序号
                    List<BookItem> bookItemsList = bookItemMapper.selectList(new LambdaQueryWrapper<BookItem>().eq(BookItem::getBookId, chapter.getId()).orderByAsc(BookItem::getCreateTime));
                    List<BookItem> collect = bookItemsList.stream().filter(bookItem -> bookItem.getBookId().equals(chapter.getId())).collect(Collectors.toList());
                    collect.stream().filter(bookItem -> bookItem.getItemId().equals(clozeItem.getId())).findFirst().ifPresent(bookItem -> resp.setCurrent(collect.indexOf(bookItem) + 1));
                    result.add(resp);

                });
            }
        }
        return result;
    }

    /**
     * 获取错题列表
     * @param account 当前用户账号
     * @return 错图列表
     */
    @Override
    public List<WrongItemListResp> getWrongItemList(String account) {
        // 查询当前用户做题记录
        LambdaQueryWrapper<ItemStudent> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ItemStudent::getAccount, account);
        queryWrapper.orderByDesc(ItemStudent::getUpdateTime);
        List<ItemStudent> itemStudents = this.list(queryWrapper);

        List<Long> ids = itemStudents.stream().map(ItemStudent::getItemId).collect(Collectors.toList());

        // 准备数据
        List<BookItem> bookItems = bookItemMapper.selectList(new LambdaQueryWrapper<BookItem>()
                .in(!CollectionUtils.isEmpty(ids), BookItem::getItemId, ids)
                .apply(CollectionUtils.isEmpty(ids), "1 != 1"));
        List<Book> books = bookService.getBookList();

        // 构造结果集
        return itemStudents.stream().map(itemStudent -> {
            WrongItemListResp resp = new WrongItemListResp();
            resp.setItemId(itemStudent.getItemId());
            resp.setType(itemStudent.getItemType());
            resp.setWrongCount(itemStudent.getWrongCount());
            if (itemStudent.getItemType().equals(AppProperties.ITEM_TYPE_SUBJECT)) {
                Optional.ofNullable(subjectItemService.getSubjectItemById(itemStudent.getItemId()))
                        .ifPresent(subjectItem -> {
                            resp.setContent(subjectItem.getContent());
                            List<BookListResult> bookList = bookService.getBooksOfItem(subjectItem.getId(), bookItems, books).get(0);
                            Collections.reverse(bookList);
                            resp.setChapter(bookList.stream().map(BookListResult::getName).collect(Collectors.joining("/")));
                        });
            } else {
                Optional.ofNullable(clozeItemService.getClozeItemById(itemStudent.getItemId()))
                        .ifPresent(clozeItem -> {
                            resp.setContent(clozeItem.getMarkContent());
                            List<BookListResult> bookList = bookService.getBooksOfItem(clozeItem.getId(), bookItems, books).get(0);
                            Collections.reverse(bookList);
                            resp.setChapter(bookList.stream().map(BookListResult::getName).collect(Collectors.joining("/")));

                        });
            }
            resp.setTime(itemStudent.getUpdateTime());
            return resp;
        }).collect(Collectors.toList());
    }

    /**
     * 获取错题详细
     * @param current 当前数
     * @param account 当前用户账号
     * @return 错题详细
     */
    @Override
    public PageR<WrongItemDetailResp> getWrongItemDetail(Integer current, String account) {
        // 构造查询条件
        Page<ItemStudent> page = new Page<>(current, 1);
        page.addOrder(OrderItem.desc("update_time"));
        LambdaQueryWrapper<ItemStudent> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ItemStudent::getAccount, account);
        // 查询数据
        this.page(page, queryWrapper);
        // 准备数据
        List<Book> books = bookService.getBookList();
        // 构造结果集
        PageR<WrongItemDetailResp> pageR = new PageR<>();
        BeanUtils.copyProperties(page, pageR, "records");

        ItemStudent itemStudent = page.getRecords().get(0);
        WrongItemDetailResp resp = new WrongItemDetailResp();
        resp.setId(itemStudent.getId());
        resp.setType(itemStudent.getItemType());
        resp.setWrongCount(itemStudent.getWrongCount());
        if (itemStudent.getItemType().equals(AppProperties.ITEM_TYPE_SUBJECT)) {
            SubjectItem subjectItem = subjectItemService.getSubjectItemById(itemStudent.getItemId());
            List<BookItem> bookItems = bookItemMapper.selectList(new LambdaQueryWrapper<BookItem>().eq(BookItem::getItemId, subjectItem.getId()));
            // 查询章节
            List<BookListResult> bookListResults = bookService.getBooksOfItem(subjectItem.getId(), bookItems, books).get(0);
            Collections.reverse(bookListResults);
            resp.setChapter(bookListResults.stream().map(BookListResult::getName).collect(Collectors.joining("/")));
            // 封装其他信息
            resp.setGender(subjectItem.getGender());
            resp.setAge(subjectItem.getAge());
            Code difficulty = codeService.getById(subjectItem.getDifficultyId());
            resp.setDifficulty(difficulty != null ? difficulty.getName() : null);
            resp.setKnowledgePoints(Arrays.asList(subjectItem.getKnowledgePoint().split("\\|")));
            resp.setContent(subjectItem.getContent());
            // 查询是否收藏
            LambdaQueryWrapper<Collect> collectLambdaQueryWrapper = new LambdaQueryWrapper<>();
            collectLambdaQueryWrapper.eq(Collect::getItemId, subjectItem.getId()).eq(Collect::getAccount, account);
            resp.setIsCollect(collectService.count(collectLambdaQueryWrapper) != 0 ? 1 : 0);
            // 查询关联图片
            List<Image> images = imageService.getImagesByItemId(subjectItem.getId());
            resp.setImages(images.stream().map(Image::getRemoteFileUrl).collect(Collectors.toList()));
            // 获取总分
            resp.setScore(itemService.calculateItemTotalScore(subjectItem));
            // 构造问题，计算总分
            List<WrongItemDetailResp.SubjectQuestion> questions = new ArrayList<>();
            if (StringUtils.hasText(subjectItem.getAnsDiagnose())) {
                questions.add(new WrongItemDetailResp.SubjectQuestion("diagnose", "请诊断该患者的病症是什么？", Arrays.asList(subjectItem.getTipDiagnose().split("\\|")), subjectItem.getAnsDiagnose()));
            }
            if (StringUtils.hasText(subjectItem.getAnsCause())) {
                questions.add(new WrongItemDetailResp.SubjectQuestion("cause", "请问该患者的病机是什么？", Arrays.asList(subjectItem.getTipCause().split("\\|")), subjectItem.getAnsCause()));
            }
            if (StringUtils.hasText(subjectItem.getAnsMethod())) {
                questions.add(new WrongItemDetailResp.SubjectQuestion("method", "请问该患者的治法是什么？", Arrays.asList(subjectItem.getTipMethod().split("\\|")), subjectItem.getAnsMethod()));
            }
            if (StringUtils.hasText(subjectItem.getAnsPrescription())) {
                questions.add(new WrongItemDetailResp.SubjectQuestion("prescription", "请问该患者开的处方是什么？", Arrays.asList(subjectItem.getTipPrescription().split("\\|")), subjectItem.getAnsPrescription()));
            }
            if (StringUtils.hasText(subjectItem.getAnsMedicine())) {
                questions.add(new WrongItemDetailResp.SubjectQuestion("medicine", "请问该患者开的药物是什么？", Arrays.asList(subjectItem.getTipMedicine().split("\\|")), subjectItem.getAnsMedicine()));

            }
            resp.setQuestions(questions);
            resp.setTime(itemStudent.getUpdateTime());
        } else {
            ClozeItem clozeItem = clozeItemService.getClozeItemById(itemStudent.getItemId());
            List<BookItem> bookItems = bookItemMapper.selectList(new LambdaQueryWrapper<BookItem>().eq(BookItem::getItemId, clozeItem.getId()));
            // 查询难易级别
            Code difficulty = codeService.getById(clozeItem.getDifficultyId());
            resp.setDifficulty(difficulty != null ? difficulty.getName() : null);
            resp.setKnowledgePoints(Arrays.asList(clozeItem.getKnowledgePoint().split("\\|")));
            resp.setContent(clozeItem.getMarkContent());
            // 查询是否收藏
            LambdaQueryWrapper<Collect> collectLambdaQueryWrapper = new LambdaQueryWrapper<>();
            collectLambdaQueryWrapper.eq(Collect::getItemId, clozeItem.getId()).eq(Collect::getAccount, account);
            resp.setIsCollect(collectService.count(collectLambdaQueryWrapper) != 0 ? 1 : 0);
            // 查询关联图片
            List<Image> images = imageService.getImagesByItemId(clozeItem.getId());
            resp.setImages(images.stream().map(Image::getRemoteFileUrl).collect(Collectors.toList()));
            // 计算总分
            resp.setScore(itemService.calculateItemTotalScore(clozeItem));
            // 查询章节
            List<BookListResult> bookListResults = bookService.getBooksOfItem(clozeItem.getId(), bookItems, books).get(0);
            Collections.reverse(bookListResults);
            resp.setChapter(bookListResults.stream().map(BookListResult::getName).collect(Collectors.joining("/")));
            resp.setTime(itemStudent.getUpdateTime());
            resp.setAns(clozeItem.getAns());
        }
        pageR.setRecords(new ArrayList<WrongItemDetailResp>() {{
            add(resp);
        }});
        return pageR;
    }

    @Override
    public PageR<ItemStudentHistoryResult> getStudentHistoryByTeacher(Integer page, Integer pageSize, String account, Long currUserId, String currAccount) {
        Page<ItemStudent> itemStudentPage = new Page<>(page, pageSize);
        itemStudentPage.addOrder(OrderItem.desc("update_time"));

        // 构造查询条件
        LambdaQueryWrapper<ItemStudent> queryWrapper = new LambdaQueryWrapper<>();
        if (!roleService.isAdministrator(currUserId)) {// 如果不是管理员则仅可以查看自己所教班级的数据
            List<String> accounts = teacherMapper.selectStudentAccountByTeacherAccount(currAccount);
            queryWrapper.in(!CollectionUtils.isEmpty(accounts), ItemStudent::getAccount, accounts);
            queryWrapper.apply(CollectionUtils.isEmpty(accounts), "1 != 1");
        }
        queryWrapper.eq(StringUtils.hasText(account), ItemStudent::getAccount, account);

        this.page(itemStudentPage, queryWrapper);

        PageR<ItemStudentHistoryResult> pageR = new PageR<>();
        BeanUtils.copyProperties(itemStudentPage, pageR, "records");

        List<ItemStudent> itemStudentList = itemStudentPage.getRecords();

        // 获取主观题ID列表
        List<Long> subjectIds = itemStudentList
                .stream()
                .filter(itemStudent -> itemStudent.getItemType().equals(AppProperties.ITEM_TYPE_SUBJECT))
                .map(ItemStudent::getItemId)
                .collect(Collectors.toList());
        // 获取填空题ID列表
        List<Long> clozeIds = itemStudentList
                .stream()
                .filter(itemStudent -> itemStudent.getItemType().equals(AppProperties.ITEM_TYPE_CLOZE))
                .map(ItemStudent::getItemId)
                .collect(Collectors.toList());
        // 准备数据
        List<Long> ids = itemStudentList.stream().map(ItemStudent::getItemId).collect(Collectors.toList());
        List<BookItem> bookItems = bookItemMapper.selectList(
                new LambdaQueryWrapper<BookItem>()
                        .in(!CollectionUtils.isEmpty(ids), BookItem::getItemId, ids)
                        .apply(CollectionUtils.isEmpty(ids), "1 != 1")
                        .orderByAsc(BookItem::getCreateTime));
        List<Book> books = bookService.getBookList();
        // 构造结果集
        List<ItemStudentHistoryResult> result = new ArrayList<>();
        // 获取题目信息
        List<SubjectItem> subjectItems = CollectionUtils.isEmpty(subjectIds) ? null : subjectItemService.listByIds(subjectIds);
        List<ClozeItem> clozeItems = CollectionUtils.isEmpty(clozeIds) ? null : clozeItemService.listByIds(clozeIds);
        itemStudentList.forEach(itemStudent -> {
            ItemStudentHistoryResult resp = new ItemStudentHistoryResult();
            BeanUtils.copyProperties(itemStudent, resp);
            User user = userService.getUserByAccount(itemStudent.getAccount());
            resp.setName(user.getName());
            Optional.ofNullable(user.getAvatar()).ifPresent(id -> resp.setAvatarUrl(imageService.getImageById(id).getRemoteFileUrl()));
            // 判断题目类型
            if (itemStudent.getItemType().equals(AppProperties.ITEM_TYPE_SUBJECT) && subjectItems != null) {
                subjectItems.stream().filter(subjectItem -> subjectItem.getId().equals(itemStudent.getItemId())).findFirst().ifPresent(subjectItem -> {
                    // 获取题目所属章节
                    List<BookListResult> bookListResults = bookService.getBooksOfItem(subjectItem.getId(), bookItems, books).get(0);
                    BookListResult chapter = bookListResults.get(0);
                    resp.setChapterId(chapter.getId());
                    Collections.reverse(bookListResults);
                    resp.setChapter(bookListResults.stream().map(BookListResult::getName).collect(Collectors.joining("/")));
                    resp.setContent(subjectItem.getContent());
                    resp.setTime(itemStudent.getCreateTime());
                });
            } else if (itemStudent.getItemType().equals(AppProperties.ITEM_TYPE_CLOZE) && clozeItems != null) {
                clozeItems.stream().filter(clozeItem -> clozeItem.getId().equals(itemStudent.getItemId())).findFirst().ifPresent(clozeItem -> {
                    List<BookListResult> bookListResults = bookService.getBooksOfItem(clozeItem.getId(), bookItems, books).get(0);
                    BookListResult chapter = bookListResults.get(0);
                    resp.setChapterId(chapter.getId());
                    Collections.reverse(bookListResults);
                    resp.setChapter(bookListResults.stream().map(BookListResult::getName).collect(Collectors.joining("/")));
                    resp.setContent(clozeItem.getMarkContent());
                    resp.setTime(itemStudent.getCreateTime());
                });
            }
            result.add(resp);
        });
        pageR.setRecords(result);
        return pageR;
    }

}




